<?php

namespace pmvc\mvc\controller;

use pmvc\ioc\ObjectFactory;
use pmvc\ioc\ObjectFactoryAware;
use pmvc\mvc\MappedObject;
use pmvc\mvc\ControllerMapping;
use pmvc\mvc\Controller;
use pmvc\mvc\Request;
use pmvc\util\ReflectionUtil;
use pmvc\util\StringUtil;
use pmvc\log\Log;
use Exception;

class ObjectNameControllerMapping 
	implements ObjectFactoryAware,
	ControllerMapping {

	private $objectFactory;
	private $enableRegex 			= false;
	private $enableTokenReplacement	= false;
	private $regexPrefix			= "regex:";

	public function setObjectFactory(ObjectFactory $objectFactory) {
		$this->objectFactory = $objectFactory;
	}

	public function getController($url, Request $request) {

		// try exact match on name
		if ($this->objectFactory->hasObjectWithName($url, true)) {
			$obj = $this->objectFactory->getObjectByName($url);
			$desc = $this->objectFactory->getDescriptorByName($url);
			Log::trace(__CLASS__, "url: {0} matches: {1} for: {2}", $url, $url, $desc->class);
			return new MappedObject($obj, $url);

		// try regex or token replacement
		} else if ($this->enableRegex || $this->enableTokenReplacement) {

			// get each object name
			foreach ($this->objectFactory->getObjectNames() as $name) {

				// try regex
				if ($this->enableRegex && StringUtil::startsWith($name, $this->regexPrefix)) {
					$regex = substr($name, strlen($this->regexPrefix));
					if (StringUtil::matches($regex, $url, false)) {
						$obj = $this->objectFactory->getObjectByName($name);
						$desc = $this->objectFactory->getDescriptorByName($name);
						Log::trace(__CLASS__, "url: {0} matches: {1} for: {2}", $url, $regex, $desc->class);
						return new MappedObject($obj, $regex);
					}
				}

				// try token replacement
				if ($this->enableTokenReplacement) {
					$regex = "^".preg_replace("\1".'\{([^\/\{\}]+)\}'."\1", '(?<$1>[^\/\{\}]+)', $name)."$";
					if (StringUtil::matches($regex, $url, false)) {
						$obj = $this->objectFactory->getObjectByName($name);
						$desc = $this->objectFactory->getDescriptorByName($name);
						Log::trace(__CLASS__, "url: {0} matches: {1} for: {2}", $url, $regex, $desc->class);
						return new MappedObject($obj, $regex);
					}
					
				}
			}
		}

		// no good
		return null;
	}

	public function setEnableRegex($enableRegex) {
		$this->enableRegex = $enableRegex;
	}

	public function setEnableTokenReplacement($enableTokenReplacement) {
		$this->enableTokenReplacement = $enableTokenReplacement;
	}

	public function setRegexPrefix($regexPrefix) {
		$this->regexPrefix = $regexPrefix;
	}
}

?>